package data.platform.rest.domain;

import data.platform.common.stream.aggregates.Rule;
import data.platform.common.stream.valueobjects.*;
import data.platform.common.util.DateUtil;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Setter
@Getter
@NoArgsConstructor
public class RuleVO {

    private String id;

    private String name;

    private String ruleState;

    private Map<String, Set<String>> tags;

    private String windowType;

    private int windowSize;

    private int waterMark;

    private boolean expand = false;

    private List<WorkingTimeWindowVO> workingTimeWindowVOs;

    private List<RuleMetricConditionVO> ruleMetricConditionVOs;

    public Rule toRule() {
        Rule rule = new Rule();
        rule.setId(this.id);
        rule.setName(this.name);
        rule.setRuleState(RuleState.fromString(this.ruleState));
        rule.setWindowType(WindowType.fromString(this.windowType));
        rule.setWindowSize(this.windowSize);
        rule.setWaterMark(this.waterMark);
        rule.setTags(this.tags);

        List<WorkingTimeWindow> workingTimeWindows = new ArrayList<>();
        for(WorkingTimeWindowVO workingTimeWindowVO : this.workingTimeWindowVOs) {
            WorkingTimeWindow workingTimeWindow = new WorkingTimeWindow();
            workingTimeWindow.setBeginTime(DateUtil.getLocalTimeOfTimestamp(workingTimeWindowVO.getBeginTime()));
            workingTimeWindow.setEndTime(DateUtil.getLocalTimeOfTimestamp(workingTimeWindowVO.getEndTime()));

            workingTimeWindows.add(workingTimeWindow);
        }
        rule.setWorkingTimeWindows(workingTimeWindows);

        List<RuleMetricCondition> ruleMetricConditions = new ArrayList<>();
        for(RuleMetricConditionVO conditionVO : this.ruleMetricConditionVOs) {
            RuleMetricCondition ruleMetricCondition = new RuleMetricCondition();
            ruleMetricCondition.setMetric(conditionVO.getMetric());
            ruleMetricCondition.setAggregatorFunctionType(AggregatorFunctionType.fromString(conditionVO.getAggregatorFunctionType()));
            ruleMetricCondition.setLimitOperatorType(LimitOperatorType.fromString(conditionVO.getLimitOperatorType()));
            ruleMetricCondition.setLimit(conditionVO.getLimit());

            ruleMetricConditions.add(ruleMetricCondition);
        }

        rule.setRuleMetricConditions(ruleMetricConditions);

        return rule;
    }

    public static RuleVO toRuleVO(Rule rule) {
        RuleVO vo = new RuleVO();
        vo.setId(rule.getId());
        vo.setName(rule.getName());
        vo.setRuleState(rule.getRuleState().getName());
        vo.setTags(rule.getTags());
        vo.setWindowType(rule.getWindowType().getName());
        vo.setWindowSize(rule.getWindowSize());
        vo.setWaterMark(rule.getWaterMark());

        List<WorkingTimeWindowVO> workingTimeWindowVOS = rule.getWorkingTimeWindows().stream()
                .map(workingTimeWindow -> {
                    WorkingTimeWindowVO workingTimeWindowVO = new WorkingTimeWindowVO();
                    workingTimeWindowVO.setBeginTime(DateUtil.getDateOfLocalTime(workingTimeWindow.getBeginTime()).getTime());
                    workingTimeWindowVO.setEndTime(DateUtil.getDateOfLocalTime(workingTimeWindow.getEndTime()).getTime());
                    return workingTimeWindowVO;
                })
                .collect(Collectors.toList());
        vo.setWorkingTimeWindowVOs(workingTimeWindowVOS);

        List<RuleMetricConditionVO> ruleMetricConditionVOList = rule.getRuleMetricConditions().stream()
                .map(ruleMetricCondition -> {
                    RuleMetricConditionVO conditionVO = new RuleMetricConditionVO();
                    conditionVO.setMetric(ruleMetricCondition.getMetric());
                    conditionVO.setAggregatorFunctionType(ruleMetricCondition.getAggregatorFunctionType().getName());
                    conditionVO.setLimitOperatorType(ruleMetricCondition.getLimitOperatorType().getOperator());
                    conditionVO.setLimit(ruleMetricCondition.getLimit());
                    return conditionVO;
                }).collect(Collectors.toList());
        vo.setRuleMetricConditionVOs(ruleMetricConditionVOList);
        return vo;
    }
}
